package giftmail.common;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import giftmail.annotation.SystemLog;
import giftmail.model.TSysOperationLog;
import giftmail.model.User;
import giftmail.service.ITSysOperationLogService;
import giftmail.staticentity.SessionInfo;

/**
 * 切点类
 * @author Demo
 * @since 2017-08-24
 */
@Aspect
@Component
public class SystemLogAspect {

	 //本地异常日志记录对象    
    private  static  final Logger logger = LoggerFactory.getLogger(SystemLogAspect.class);  
	
    @Autowired
    private ITSysOperationLogService operationLogService;
    
    //Controller层切入点
    @Pointcut("@annotation(giftmail.annotation.SystemLog)")
    public  void logAspect() {
    }
    
    /**
     * 切入点之后,操作(有助于保证session一定有效,并且能记录到数据库中)
     * ********2017-08-25*******  
     * 修改了一次代码:之前是@Before,现在是@After
     * 原因:Before会记录session为空的情况;而After可以记录准确的session有效
     * @param joinPoint 切点
     */
    @After("logAspect()")
    public  void doAfter(JoinPoint joinPoint) {
    	HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpSession session = request.getSession();
        //读取session中的用户
        User user = (User) session.getAttribute(SessionInfo.SESSION_LOGIN_USER);
        try {
            //请求的IP
            String requestURI = request.getRequestURI().toString();
            String ip = request.getRemoteAddr();
            String funname = getLogParamMap(joinPoint).get("funname").toString();
            String memo = getLogParamMap(joinPoint).get("memo").toString();

            logger.info("=====记录系统操作日志开始=====");

            logger.info("请求URL:" + requestURI);
            logger.info("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
            logger.info("请求功能:" + funname);
            logger.info("功能描述:" + memo);
            if (user != null) {
                logger.info("请求人:" + user.getName());
            }
            logger.info("请求IP:" + ip);

            // 记录系统操作日志到数据库
            TSysOperationLog tSysOperationLog = new TSysOperationLog();
            
            tSysOperationLog.setOperationLogFunname(funname);
            tSysOperationLog.setOperationLogMemo(memo);
            if (user != null) {
                tSysOperationLog.setOperationLogUserid(user.getName());
            }
            tSysOperationLog.setOperationLogTime(new Date());
            tSysOperationLog.setOperationLogIp(ip);
            operationLogService.insert(tSysOperationLog);

            logger.info("=====记录系统操作日志结束=====");
        }  catch (Exception e) {
            //记录本地异常日志
            logger.error("==记录系统操作日志异常==");
            logger.error("异常信息:{}",e);
        }
        
    }
    
    /**
     * 获取注解中对方法的描述信息 用于Controller层注解
     *
     * @param joinPoint 切点
     * @return 方法描述
     * @throws Exception
     */
    public static Map getLogParamMap(JoinPoint joinPoint)  throws Exception {
        Map<String, String> map = new HashMap<String, String>();

        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        String description = "";
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
                    map.put("funname", method.getAnnotation(SystemLog.class).funname());
                    map.put("memo", method.getAnnotation(SystemLog.class).memo());
                    break;
                }
            }
        }
        return map;
    }
}
